//
// gcssai_security.cpp
// gcs
// Grand Central Station, controlling process of the Protea Application Server / Business Logic Transactions for SAI security and user management
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Please send correspondence to:
// 
// theproteaproject@gmail.com
//

// gcssai.cpp
//
// Contains the SAI transactions, compiled into GCS
//

#include "../SDK/ToolsInterface.h"
#include "../AppHandler/parms_xml.h"
#include "gcs.h"
#include "security_editor.h"

//////////////////////////////////////////////////////////////////////
//
// USERS
//
//////////////////////////////////////////////////////////////////////



//@ SEC 2
//@ CHA ListUsers
//@ COD ListUsers
//@ NUM 15
TRANSACTION_CODE( XCGCS::ListUsers )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( ListUsers );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			//@ Create the child buffer
			detail = CreateBuffer( child, false );

			//@ While we have users
			XCUserPointer* users = auth.users.GetUserList();
			while (users) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				//@ Fill in the user name on the detail buffer
				detail->GetField( FLD_USER_NAME )->SetString( users->info->name );

				//@ Set the description
				temp = detail->GetField( FLD_DESCRIPTION );
				if (temp)
					temp->SetString( users->info->description );

				//@ Send the response
				TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

				//@ Move on to next record
				users = users->next;

				//@ GRE
			};
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};





//@ SEC 2
//@ CHA Review User
//@ COD ReviewUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::ReviewUser )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( ReviewUser );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		//@ Obtain the user record
		const XCUserInformation* user = auth.users.Find( txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr() );
		if (!user)
			txnvars.Errors->Add( 1, SEV_CRITICAL );

		//@ Set the description
		temp = txnvars.buffer->GetField( FLD_DESCRIPTION );
		if (temp)
			temp->SetString( user->description );

		//@ Return user information
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			XCGroupInformation* groups = auth.groups.GetGroupList();

			//@ Create the child buffer
			detail = CreateBuffer( child, false );

			//@ Find all groups that user belongs to
			while (groups) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				if (groups->ContainsUser( user->index )) {
					//@ Set the group name
					detail->GetField( FLD_USER_NAME )->SetString( groups->name );

					//@ Send the response
					TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
				};

				//@ Move on to next record
				groups = groups->next_group;

				//@ GRE
			};
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};






//@ SEC 2
//@ CHA Add User
//@ COD AddUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::AddUser )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( AddUser );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		const char* user_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();
		const char* user_descr = NULL;
		const char* user_password = NULL;

		temp = txnvars.buffer->GetField( FLD_DESCRIPTION );
		if (temp)
			user_descr = temp->GetStringPtr();

		temp = txnvars.buffer->GetField( FLD_USER_PASSWORD );
		if (temp)
			user_password = temp->GetStringPtr();

		//@ Attempt to obtain the user record
		//@ ERR C (ALREADY_EXISTS) User already exists
		const XCUserInformation* user = auth.users.Find( txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr() );
		if (user)
			txnvars.Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );

		//@ Create a new user
		auth.AddUser( user_name, user_password, user_descr );

		//@ Clear out the password field
		temp->Clear();

		//@ Return user information
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};




//@ SEC 2
//@ CHA Remove User
//@ COD RemoveUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::RemoveUser )
{
	XCBuffer* detail = NULL;
	START_TXN( RemoveUser );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );
		const char* user_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();

		//@ Attempt to obtain the user record, if not, then
		//@ ERR C (DOESNT_EXIST) User doesn't exist
		const XCUserInformation* user = auth.users.Find( txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr() );
		if (!user)
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );

		// Remove the user from the group
		auth.RemoveUser( user_name );

		// Return user information
		txnvars.buffer->Clear();
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};





//@ SEC 2
//@ CHA Change User
//@ COD ChangeUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::ChangeUser )
{
	XCBuffer* detail = NULL;
	START_TXN( ChangeUser );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );
		const char* user_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();

		//@ Attempt to obtain the user record, if not, then
		//@ ERR C (DOESNT_EXIST) User doesn't exist
		const XCUserInformation* user = auth.users.Find( user_name );
		if (!user)
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );

		// Update the user
		const char* password = txnvars.buffer->GetField( FLD_USER_PASSWORD )->GetStringPtr();
		const char* description = txnvars.buffer->GetField( FLD_DESCRIPTION )->GetStringPtr();

		if (transaction->GetTransNumber() == TRANS_CHG_USER)
			auth.UpdateUser( user_name, NULL, description );
		else
			auth.UpdateUser( user_name, password, NULL );

		// Return user information
		txnvars.buffer->Clear();
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};





//////////////////////////////////////////////////////////////////////
//
// GROUPS
//
//////////////////////////////////////////////////////////////////////


//@ SEC 2
//@ CHA List Groups
//@ COD ListGroups
//@ NUM 15
TRANSACTION_CODE( XCGCS::ListGroups )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( ListGroups );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			//@ Create the detail buffer
			detail = CreateBuffer( child, false );

			//@ For each group:
			XCGroupInformation* group = auth.groups.GetGroupList();
			while (group) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				//@ Get data
				detail->GetField( FLD_USER_NAME )->SetString( group->name );

				//@ Set the description
				temp = detail->GetField( FLD_DESCRIPTION );
				if (temp)
					temp->SetString( group->description );

				//@ Send the response
				TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

				//@ Move on to next record
				group = group->next_group;

				//@ GRE
			};
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};




//@ SEC 2
//@ CHA Review Group
//@ COD ReviewGroup
//@ NUM 15
TRANSACTION_CODE( XCGCS::ReviewGroup )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( ReviewGroup );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		//@ Obtain the group record
		const XCGroupInformation* group = auth.groups.Find( txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr() );
		if (!group)
			txnvars.Errors->Add( 1, SEV_CRITICAL );

		//@ Set the description
		temp = txnvars.buffer->GetField( FLD_DESCRIPTION );
		if (temp)
			temp->SetString( group->description );

		//@ Return group information
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

		//@ Output group membership:
		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			//@ GRS
			XCUserPointer* users = group->users;

			//@ Create the detail buffer
			detail = CreateBuffer( child, false );

			//@ For each user in the group:
			while (users) {
				//@ GRS
				const XCUserInformation* user = users->info;

				//@ Clear the detail buffer
				detail->Clear();

				//@ Set the group name
				detail->GetField( FLD_USER_NAME )->SetString( user->name );

				//@ Send the response
				TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

				//@ Move on to next record
				users = users->next;

				//@ GRE
			};
			//@ GRE
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};






//@ SEC 2
//@ CHA Add Group
//@ COD AddGroup
//@ NUM 15
TRANSACTION_CODE( XCGCS::AddGroup )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( AddGroup );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		const char* group_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();
		const char* group_descr = NULL;

		temp = txnvars.buffer->GetField( FLD_DESCRIPTION );
		if (temp)
			group_descr = temp->GetStringPtr();

		//@ Obtain the group record
		//@ ERR C (1)
		const XCGroupInformation* group = auth.groups.Find( group_name );
		if (group)
			txnvars.Errors->Add( 1, SEV_CRITICAL );

		//@ Create a new group
		auth.AddGroup( group_name, group_descr );

		//@ Return user information
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};




//@ SEC 2
//@ CHA Remove Group
//@ COD RemoveGroup
//@ NUM 15
TRANSACTION_CODE( XCGCS::RemoveGroup )
{
	XCBuffer* detail = NULL;
	START_TXN( RemoveGroup );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );
		const char* group_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();

		//@ Obtain the group record
		//@ ERR C (1)
		const XCGroupInformation* group = auth.groups.Find( group_name );
		if (!group)
			txnvars.Errors->Add( 1, SEV_CRITICAL );

		//@ Remove the user from the group
		auth.RemoveGroup( group_name );

		//@ Return user information
		txnvars.buffer->Clear();
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};




//////////////////////////////////////////////////////////////////////
//
// USER/GROUP relationships
//
//////////////////////////////////////////////////////////////////////


//@ SEC 2
//@ CHA Remove User From Group
//@ COD RemoveUserFromGroup
//@ NUM 15
TRANSACTION_CODE( XCGCS::RemoveUserFromGroup )
{
	XCBuffer* detail = NULL;
	START_TXN( RemoveUserFromGroup );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );
		const char* group_name = txnvars.buffer->GetField( FLD_GROUP_NAME )->GetStringPtr();
		const char* user_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();

		//@ Obtain the group record
		//@ ERR C (DOESNT_EXIST) Group doesn't exist
		const XCGroupInformation* group = auth.groups.Find( group_name );
		if (!group)
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_GROUP_NAME, 1, ERR_GROUP );

		//@ Obtain the user record
		//@ ERR C (DOESNT_EXIST) User doesn't exist
		const XCUserInformation* user = auth.users.Find( user_name );
		if (!user)
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );

		//@ Remove the user from the group
		auth.RemoveUserFromGroup( user_name, group_name );

		//@ Return user information
		txnvars.buffer->Clear();
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};



//@ SEC 2
//@ CHA Add User To Group
//@ COD AddUserToGroup
//@ NUM 15
TRANSACTION_CODE( XCGCS::AddUserToGroup )
{
	XCBuffer* detail = NULL;
	START_TXN( AddUserToGroup );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );
		const char* group_name = txnvars.buffer->GetField( FLD_GROUP_NAME )->GetStringPtr();
		const char* user_name = txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr();

		//@ Obtain the group record
		//@ ERR C (DOESNT_EXIST) Group doesn't exist
		const XCGroupInformation* group = auth.groups.Find( group_name );
		if (!group)
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_GROUP_NAME, 1, ERR_GROUP );

		//@ Obtain the user record
		//@ ERR C (DOESNT_EXIST) User doesn't exist
		const XCUserInformation* user = auth.users.Find( user_name );
		if (!user)
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );

		//@ Remove the user from the group
		auth.AddUserToGroup( user_name, group_name );

		//@ Return user information
		txnvars.buffer->Clear();
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};



//////////////////////////////////////////////////////////////////////
//
// APPLICATIONS
//
//////////////////////////////////////////////////////////////////////



//@ SEC 2
//@ CHA ListApplications
//@ COD ListApplications
//@ NUM 15
TRANSACTION_CODE( XCGCS::ListApplications )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( ListApplications );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			//@ Create the child buffer
			detail = CreateBuffer( child, false );

			//@ While we have users
			XCSecurityApplication* app = auth.apps.applist;
			while (app) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				//@ Fill in the application number on the detail buffer
				detail->GetField( FLD_APPL_NBR )->SetLong( app->number );

				//@ Set the default allow flag
				temp = detail->GetField( FLD_ALLOW_ALL_DEFLT );
				if (temp)
					temp->SetBool( app->default_allow );

				//@ Send the response
				TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

				//@ Move on to next record
				app = app->next;

				//@ GRE
			};
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};





//@ SEC 2
//@ CHA Review Application
//@ COD ReviewApplication
//@ NUM 15
TRANSACTION_CODE( XCGCS::ReviewApplication )
{
	XCBuffer* detail = NULL;

	XCField* temp = NULL;

	START_TXN( ReviewUser );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		//@ Obtain the user record
		const XCUserInformation* user = auth.users.Find( txnvars.buffer->GetField( FLD_USER_NAME )->GetStringPtr() );
		if (!user)
			txnvars.Errors->Add( 1, SEV_CRITICAL );

		//@ Set the description
		temp = txnvars.buffer->GetField( FLD_DESCRIPTION );
		if (temp)
			temp->SetString( user->description );

		//@ Set the password
		temp = txnvars.buffer->GetField( FLD_USER_PASSWORD );
		if (temp)
			temp->SetString( user->password );

		//@ Return user information
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			XCGroupInformation* groups = auth.groups.GetGroupList();

			//@ Create the child buffer
			detail = CreateBuffer( child, false );

			//@ Find all groups that user belongs to
			while (groups) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				if (groups->ContainsUser( user->index )) {
					//@ Set the group name
					detail->GetField( FLD_USER_NAME )->SetString( groups->name );

					//@ Send the response
					TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
				};

				//@ Move on to next record
				groups = groups->next_group;

				//@ GRE
			};
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};




//@ SEC 2
//@ CHA Review Application Sub Item
//@ COD ReviewApplicationSubItem
//@ NUM 15
TRANSACTION_CODE( XCGCS::ReviewApplicationSubItem )
{
	XCBuffer* detail = NULL;

	START_TXN( ReviewApplicationSubItem );
		const XCSecurityRuleList* rules = NULL;
		const XCSecurityItems* items = NULL;
		const XCSecurityApplication* app;

		int app_number = txnvars.buffer->GetField( FLD_APPL_NBR )->GetLong( true );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		//@ Obtain the application record
		app = auth.apps.GetApplication( app_number );
		if (!app)
			txnvars.Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_APPL_NBR, 1, ERR_APPLICATION );

		//@ Determine which component we need information on
		int component = txnvars.buffer->GetField( FLD_INFO_TYPE )->GetLong( true );
		switch( component ) {
			case 0:	// Base application
				rules = app;
				break;

			case 1:	// Transactions
				rules = &app->trans;
				items = &app->trans;
				break;

			case 2: // Capabilities
				rules = &app->caps;
				items = &app->caps;
				break;

			case 3: // Data Items
				rules = &app->data_items;
				items = &app->data_items;
				break;

			default:
				txnvars.Errors->Add( 1 );
				break;
		};

		//@ Search for the item
		XCField* info_item = txnvars.buffer->GetField( FLD_INFO_ITEM );
		if (info_item && !info_item->IsBlank()) {
			long item = atoi( info_item->GetStringPtr() );

			XCSecurityItem* myitem = items->items;
			while (myitem && myitem->item_number != item)
				myitem = myitem->next;

			if (myitem) {
				rules = myitem;
				items = NULL;
			} else
				RAISETOOLSERROR( 1 );
		};

		//@ Return application information
		TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

		int child = txnvars.buffer->GetChildFormat();
		if ( child )
		{
			//@ Create the child buffer
			detail = CreateBuffer( child, false );

			//@ Submit the default rule
			detail->GetField( FLD_ALLOW_ALL_DEFLT )->SetBool( rules->default_allow );
			detail->GetField( FLD_INFO_TYPE )->SetLong( 1 );
			TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

			//@ For each rule for this component
			XCSecurityRule* rtemp = rules->rules;
			while (rtemp) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				int index = rtemp->user_group_index;
				if (index > 0) {
					// User
					XCUserInformation* user = auth.users.Find( index );

					//@ Set the user name
					detail->GetField( FLD_USER_NAME )->SetString( user->name );

					//@ Set the type
					detail->GetField( FLD_INFO_TYPE )->SetLong( 0 );
				} else {
					// Group
					XCGroupInformation* group = auth.groups.Find( -index );

					//@ Set the group name
					detail->GetField( FLD_USER_NAME )->SetString( group->name );

					//@ Set the type
					detail->GetField( FLD_INFO_TYPE )->SetLong( 1 );
				};

				detail->GetField( FLD_ALLOW_ALL_DEFLT )->SetBool( rtemp->allow );

				//@ Send the response
				TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

				//@ Move on to next record
				rtemp = rtemp->next_rule;

				//@ GRE
			};

			//@ For each item in this component
			XCSecurityItem* item = items ? items->items : NULL;
			while (item) {
				//@ GRS

				//@ Clear the detail buffer
				detail->Clear();

				//@ Set the group name
				char number[ 20 ];
				sprintf( number, "%ld", item->item_number );
				detail->GetField( FLD_USER_NAME )->SetString( number );

				//@ Set the type
				detail->GetField( FLD_INFO_TYPE )->SetLong( 2 );

				//@ Set the default allow flag
				detail->GetField( FLD_ALLOW_ALL_DEFLT )->SetBool( item->default_allow );

				//@ Send the response
				TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );

				//@ Move on to next record
				item = item->next;

				//@ GRE
			};
		};

		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};






//@ SEC 2
//@ CHA Add App Security User
//@ COD AddAppSecurityUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::AddAppSecurityUser )
{
	XCBuffer* detail = NULL;

	START_TXN( AppAppSecurityUser );
		XCSecurityRuleList* rules = NULL;
		XCSecurityItems* items = NULL;
		XCSecurityApplication* app;
		bool added = false;

		int app_number = txnvars.buffer->GetField( FLD_APPL_NBR )->GetLong( true );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		// Obtain the component number
		int component = txnvars.buffer->GetField( FLD_INFO_TYPE )->GetLong( true );

		// Obtain the default access mode
		bool default_allow_access = txnvars.buffer->GetField( FLD_ALLOW_ALL_DEFLT )->GetBool();

		// Obtain the user name
		XCField* user_name_fld = txnvars.buffer->GetField( FLD_USER_NAME );
		bool has_user = (user_name_fld && !user_name_fld->IsBlank());

		//@ Obtain the application record
		app = auth.apps.GetApplication( app_number );
		if (!app) {
			if (component != 0 || has_user)
				txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_APPL_NBR, 1, ERR_APPLICATION );
			else {
				// Create a new application record
				auth.AddApplication( app_number, default_allow_access );
			};
		} else {
			//@ Determine which component we need information on
			switch( component ) {
				case 0:	// Base application - if we make it here, the app already exists
					if (!has_user)
						txnvars.Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_APPL_NBR, 1, ERR_APPLICATION );
					else
						rules = app;
					break;

				case 1:	// Transaction
					rules = &app->trans;
					items = &app->trans;
					break;

				case 2: // Capability
					rules = &app->caps;
					items = &app->caps;
					break;

				case 3: // Data Item
					rules = &app->data_items;
					items = &app->data_items;
					break;

				default:
					txnvars.Errors->Add( 1 );
					break;
			};


			//@ Search for the item
			XCField* info_item = txnvars.buffer->GetField( FLD_INFO_ITEM );
			if (info_item && !info_item->IsBlank()) {
				long item = atoi( info_item->GetStringPtr() );

				XCSecurityItem* myitem = items->items;
				while (myitem && myitem->item_number != item)
					myitem = myitem->next;

				if (myitem) {
					rules = myitem;
					items = NULL;

					if (!has_user)
						txnvars.Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );
				} else {
					// Create new item
					auth.AddApplicationItem( items, item, default_allow_access );
					added = true;
				};
			};


			if (!added) {
				if (has_user) {
					const char* user_name = user_name_fld->GetStringPtr();
					auth.AddApplicationSecurity( rules, user_name, default_allow_access );
				} else {
					// We are trying to add a new group, w/o user, error
					txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_INFO_ITEM, 1, ERR_GROUP );
				};
			};
		};
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};





//@ SEC 2
//@ CHA Del App Security User
//@ COD DelAppSecurityUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::DelAppSecurityUser )
{
	XCBuffer* detail = NULL;

	START_TXN( DelAppSecurityUser );
		XCSecurityRuleList* rules = NULL;
		XCSecurityItems* items = NULL;
		XCSecurityApplication* app;
		bool removed = false;

		int app_number = txnvars.buffer->GetField( FLD_APPL_NBR )->GetLong( true );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		// Obtain the component number
		int component = txnvars.buffer->GetField( FLD_INFO_TYPE )->GetLong( true );

		// Obtain the user name
		XCField* user_name_fld = txnvars.buffer->GetField( FLD_USER_NAME );
		bool has_user = (user_name_fld && !user_name_fld->IsBlank());

		//@ Obtain the application record
		app = auth.apps.GetApplication( app_number );
		if (!app) {
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_APPL_NBR, 1, ERR_APPLICATION );
		} else {
			//@ Determine which component we need information on
			switch( component ) {
				case 0:	// Base application - if we make it here, the app already exists
					if (!has_user)
						txnvars.Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_APPL_NBR, 1, ERR_APPLICATION );
					else
						rules = app;
					break;

				case 1:	// Transaction
					rules = &app->trans;
					items = &app->trans;
					break;

				case 2: // Capability
					rules = &app->caps;
					items = &app->caps;
					break;

				case 3: // Data Item
					rules = &app->data_items;
					items = &app->data_items;
					break;

				default:
					txnvars.Errors->Add( 1 );
					break;
			};


			//@ Search for the item
			XCField* info_item = txnvars.buffer->GetField( FLD_INFO_ITEM );
			if (info_item && !info_item->IsBlank()) {
				long item = atoi( info_item->GetStringPtr() );

				XCSecurityItem* myitem = items->items;
				XCSecurityItem* prev = NULL;
				while (myitem && myitem->item_number != item) {
					prev = myitem;
					myitem = myitem->next;
				};

				if (myitem) {
					if (has_user) {
						// Setup to delete the user
						rules = myitem;
						items = NULL;
					} else {
						// Trying to delete the actual item
						if (prev)
							prev->next = myitem->next;
						else
							items->items = myitem->next;

						myitem->next = NULL;
						auth.RemoveApplicationItem( items, myitem );
						delete myitem;
						removed = true;
					};
				} else {
					// The item doesn't exist
					txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );
				};
			};

			if (!removed) {
				if (has_user) {
					const char* user_name = user_name_fld->GetStringPtr();
					auth.RemoveApplicationSecurity( rules, user_name );
				} else {
					// We are trying to delete a default, error
					txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_INFO_ITEM, 1, ERR_GROUP );
				};
			};
		};
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};





//@ SEC 2
//@ CHA Chg App Security User
//@ COD ChgAppSecurityUser
//@ NUM 15
TRANSACTION_CODE( XCGCS::ChgAppSecurityUser )
{
	XCBuffer* detail = NULL;

	START_TXN( ChgAppSecurityUser );
		XCSecurityRuleList* rules = NULL;
		XCSecurityItems* items = NULL;
		XCSecurityApplication* app;

		int app_number = txnvars.buffer->GetField( FLD_APPL_NBR )->GetLong( true );

		// Create the authorization tables
		XCAuthenticateEditor auth( this );

		// Obtain the component number
		int component = txnvars.buffer->GetField( FLD_INFO_TYPE )->GetLong( true );

		// Obtain the user name
		XCField* user_name_fld = txnvars.buffer->GetField( FLD_USER_NAME );
		bool has_user = (user_name_fld && !user_name_fld->IsBlank());

		//@ Obtain the application record
		app = auth.apps.GetApplication( app_number );
		if (!app) {
			txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_APPL_NBR, 1, ERR_APPLICATION );
		} else {
			//@ Determine which component we need information on
			switch( component ) {
				case 0:	// Base application - if we make it here, the app already exists
					rules = app;
					break;

				case 1:	// Transaction
					rules = &app->trans;
					items = &app->trans;
					break;

				case 2: // Capability
					rules = &app->caps;
					items = &app->caps;
					break;

				case 3: // Data Item
					rules = &app->data_items;
					items = &app->data_items;
					break;

				default:
					txnvars.Errors->Add( 1 );
					break;
			};


			//@ Search for the item
			XCField* info_item = txnvars.buffer->GetField( FLD_INFO_ITEM );
			if (info_item && !info_item->IsBlank()) {
				long item = atoi( info_item->GetStringPtr() );

				XCSecurityItem* myitem = items->items;
				XCSecurityItem* prev = NULL;
				while (myitem && myitem->item_number != item) {
					prev = myitem;
					myitem = myitem->next;
				};

				if (myitem) {
					// Point to the rules for this item
					rules = myitem;
					items = NULL;
				} else {
					// The item doesn't exist
					txnvars.Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_USER_NAME, 1, ERR_USER );
				};
			};

			// Issue the change
			const char* user_name = has_user ? user_name_fld->GetStringPtr() : NULL;
			bool default_allow_access = txnvars.buffer->GetField( FLD_ALLOW_ALL_DEFLT )->GetBool();
			auth.ChangeApplicationSecurity( rules, user_name, default_allow_access );
		};
		txnvars.result->SetSuccess( true );

	CLEANUP_TXN();
		CleanupObjects( 1, &detail );
	END_TXN();
};
